package com.yand.thinkingInJava.thinkingInJava21.threadcooperation;


import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;


/**
 * dry 制作吐司
 *
 * buttered 涂抹黄油
 *
 * jammed   涂抹果酱
 */
class Toast{
    public enum Status{DRY, BUTTERED,JAMMED}
    private Status status = Status.DRY;
    private  int id = 0;
    public Toast(int idn){
        id = idn;
    }

    public void butter(){
        status = Status.BUTTERED;
    }

    public void jam(){
        status = Status.JAMMED;
    }

    public Status getStatus(){
        return status;
    }

    public int getId(){
        return id;
    }

    public String toString(){
        return "Toast" + id + ": " + status;
    }
}

class ToastQueue extends LinkedBlockingQueue<Toast>{ }

class Toaster implements Runnable{

    private ToastQueue toastQueue;

    private int count = 0;

    private Random rand = new Random(47);

    public Toaster(ToastQueue tq){
        toastQueue = tq;
    }

    @Override
    public void run() {
        try{
            while(!Thread.interrupted()){
                TimeUnit.MILLISECONDS.sleep(100 + rand.nextInt(500));
                Toast t = new Toast(count ++);
                System.out.println(t);
                toastQueue.put(t);
            }


        }catch (InterruptedException e){
            System.out.println("Toaster interrupted");
        }

        System.out.println("Toaster off");

    }
}


//黄油
class Butterer implements Runnable{

    private ToastQueue dryQueue, butteredQueue;


    public Butterer(ToastQueue dry, ToastQueue buttered){
        dryQueue = dry;
        butteredQueue = buttered;
    }

    @Override
    public void run() {
        try{
            while(!Thread.interrupted()){
                Toast t = dryQueue.take();
                t.butter();
                System.out.println(t);
                butteredQueue.put(t);
            }

        }catch (InterruptedException e){
            System.out.println("Butterer interrupted");
        }
        System.out.println("Butterer off");
    }
}

//
class Jammer implements Runnable{

    private ToastQueue butteredQueue, finishedQueue;

    public Jammer(ToastQueue buttered, ToastQueue finished){
        butteredQueue = buttered;
        finishedQueue = finished;
    }

    @Override
    public void run() {
        try{
            while(!Thread.interrupted()){
                Toast t = butteredQueue.take();
                t.jam();
                System.out.println(t);
                finishedQueue.put(t);
            }


        }catch (InterruptedException e){
            System.out.println("Jammer interrupted");
        }

        System.out.println("Jammer off");


    }
}

class Easter implements Runnable{

    private ToastQueue finishedQueue;

    private int counter = 0;

    public Easter(ToastQueue finished){
        finishedQueue = finished;
    }


    @Override
    public void run() {
        try{
            while(!Thread.interrupted()){
                Toast t = finishedQueue.take();
                if(t.getId() != counter++ ||
                        t.getStatus() != Toast.Status.JAMMED){
                    System.out.println(">>>>Error : "+t);
                    System.exit(1);
                }else{
                    System.out.println("Chomp! "+t);
                }

            }


        }catch (InterruptedException e){
            System.out.println("Eater interrupted");
        }

        System.out.println("Eater off");
    }
}



/**
 * 有一台机器具有三个任务：一个制作吐司、一个给吐司抹黄油，另外一个在涂抹过黄油的吐司上涂果酱。
 * 该示例模拟这个过程
 */

public class ToastOMatic {

    public static void main(String [] args) throws InterruptedException {
        ToastQueue dryQueue = new ToastQueue();
        ToastQueue butteredQueue = new ToastQueue();
        ToastQueue finishedQueue = new ToastQueue();

        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(new Toaster(dryQueue));
        exec.execute(new Butterer(dryQueue,butteredQueue));
        exec.execute(new Jammer(butteredQueue,finishedQueue));
        exec.execute(new Easter(finishedQueue));

        TimeUnit.SECONDS.sleep(5);

        exec.shutdownNow();
    }

}
